use std::fmt::Display;
use std::num::{ParseIntError, TryFromIntError};
use std::str::FromStr;
use std::{fmt, fs, i32, io};

use crate::gen_title;

pub fn ch4_4_1() {
    gen_title("ch4_4_1", 18);

    let a: i32 = 10;
    let b: u16 = 100;

    if a < (b as i32) {
        println!("a<b");
    }
}

pub fn ch4_4_2() {
    let a = 3.1 as i8;
    let b = 100_i8 as i32;
    let c = 'a' as u8;

    println!("a={}, b={}, c={}", a, b, c);
}

pub fn ch4_4_3() {
    gen_title("ch4_4_3", 18);
    let mut values: [i32; 2] = [1, 2];
    let p1: *mut i32 = values.as_mut_ptr();
    let first_address = p1 as usize;
    let second_address = first_address + 4;
    let p2 = second_address as *mut i32;
    unsafe {
        *p2 += 1;
    }

    println!("values={:?}", values);
}

pub fn ch4_4_4() {
    gen_title("ch4_4_4", 18);

    let a: u8 = 10;
    let b: u16 = 1500;

    let b_: u8 = b.try_into().unwrap_or_else(|e: TryFromIntError| {
        println!("{:?}", e.to_string());
        0
    });

    println!("a={}, b={}", a, b_);
}

pub fn ch4_4_5() {
    gen_title("ch4_4_5", 18);

    #[derive(Debug)]
    struct Foo {
        x: u32,
        y: u16,
    }

    #[derive(Debug)]
    struct Bar {
        a: u32,
        b: u16,
    }

    fn reinterpret(foo: Foo) -> Bar {
        let Foo { x, y } = foo;
        Bar { a: x, b: y }
    }

    let foo = Foo { x: 10, y: 20 };
    let bar = reinterpret(foo);
    println!("bar={:?}", bar);
}

pub fn ch4_4_6() {
    gen_title("ch4_4_6", 18);

    fn foo() -> i32 {
        0
    }

    let pointer = foo as *const ();
    let function = unsafe {
        // 将裸指针转换为函数指针
        std::mem::transmute::<*const (), fn() -> i32>(pointer)
    };
    assert_eq!(function(), 0);
    println!("function={}", function());
}

pub fn ch4_4_7() {
    gen_title("ch4_4_7", 18);

    #[derive(Debug)]
    struct R<'a>(&'a i32);

    unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
        std::mem::transmute::<R<'b>, R<'static>>(r)
    }

    unsafe fn shorter_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) -> &'b mut R<'c> {
        std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
    }

    unsafe {
        let r = R(&10);
        let mut r1 = extend_lifetime(r);
        let r2 = shorter_invariant_lifetime(&mut r1);
        println!("r2={:?}", r2);
    }
}

pub fn ch4_4_pra_1() {
    gen_title("ch4_4_pra_1", 18);

    let decimal = 97.123_f32;

    let integer: u8 = decimal as u8;

    let c1: u8 = decimal as u8;
    let c3 = c1 as char;
    let c2 = integer as char;

    println!("c1={}, c2={}, c3={}", c1, c2, c3);

    assert_eq!(integer, 'a' as u8);
    println!("Success");
}

pub fn ch4_4_pra_2() {
    gen_title("ch4_4_pra_2", 18);

    assert_eq!(u8::MAX, 255);

    let v = 1000 as i32;

    println!("Success!");
}

pub fn ch4_4_pra_3() {
    gen_title("ch4_4_pra_3", 18);

    println!("1000 as u16 is {}", 1000 as u16);
    println!("1000 as u8 is {}", 1000 as u32);

    println!("1000 mod 256 is: {}", 1000 % 256);
    println!("-1 as {}", -1_i8 as u8);

    println!("300.1_f32 as u8 is {}", 300.1_f32 as u8);
    println!("-100.1_f32 as u8 is {}", -100.1_f32 as u8);

    unsafe {
        println!("300.1_f32 as u8 is {}", 300.1_f32 as u8);
        println!("-100.0 as u8 is {}", (-100.0_f32).to_int_unchecked::<u8>());
        println!("nan as u8 is {}", f32::NAN.to_int_unchecked::<u8>());
    }
}

pub fn ch4_4_pra_4() {
    gen_title("ch4_4_pra_4", 18);

    let mut values: [i32; 2] = [1, 2];
    let p1: *mut i32 = values.as_mut_ptr();
    let first_address: usize = p1 as usize;
    let second_address = first_address + 4;
    let p32: *mut i32 = second_address as *mut i32;
    unsafe {
        *p32 += 1;
    }

    println!("values={:?}", values);
}

pub fn ch4_4_pra_5() {
    gen_title("ch4_4_pra_5", 18);

    let arr: [u64; 13] = [0; 13];
    assert_eq!(std::mem::size_of_val(&arr), 8 * 13);
    let a: *const [u64] = &arr;
    let b = a as *const [u8];
    unsafe {
        assert_eq!(std::mem::size_of_val(&*b), 13);
        println!("Success!");
    }
}

pub fn ch4_4_pra_6() {
    gen_title("ch4_4_pra_6", 18);

    let my_str = "hello";

    let string1 = String::from(my_str);
    let string2 = my_str.to_string();
    let string3: String = my_str.into();

    println!(
        "string1={}, string2={}, string3={}",
        string1, string2, string3
    );
}

pub fn ch4_4_pra_7() {
    gen_title("ch4_4_pra_7", 18);

    let i1: i32 = false.into();
    let i2: i32 = i32::from(false);
    println!("i1={}, i2={}", i1, i2);

    let i32: i32 = ('a' as u8).into();
    let s: String = <u8 as Into<u8>>::into('a' as u8).to_string();

    println!("i32={}, s={}", i32, s);
}

pub fn ch4_4_pra_8() {
    gen_title("ch4_4_pra_8", 18);

    #[derive(Debug)]
    struct Number {
        value: i32,
    }

    impl From<i32> for Number {
        fn from(item: i32) -> Self {
            Number { value: item }
        }
    }

    let num = Number::from(30);
    assert_eq!(num.value, 30);
    println!("{:?}", num);

    let num: Number = 30.into();
    assert_eq!(num.value, 30);
    println!("{:?}", num);

    println!("Success!");
}

pub fn ch4_4_pra_9() {
    gen_title("ch4_4_pra_9", 18);

    #[derive(Debug)]
    enum CliError {
        IoError(io::Error),
        ParseError(ParseIntError),
    }

    impl From<io::Error> for CliError {
        fn from(error: io::Error) -> Self {
            CliError::IoError(error)
        }
    }

    impl From<ParseIntError> for CliError {
        fn from(error: ParseIntError) -> Self {
            CliError::ParseError(error)
        }
    }

    fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
        let contents = fs::read_to_string(&file_name)?;
        println!("{}", contents);
        let num: i32 = contents.trim().parse()?;
        Ok(num)
    }

    open_and_parse_file("resources/hello.txt").expect("error occurs");
}

pub fn ch4_4_pra_10() {
    gen_title("ch4_4_pra_10", 18);

    let n: i16 = 256;

    let n: u8 = n.try_into().unwrap_or_else(|e| {
        println!("there is an error when converting");
        0
    });

    assert_eq!(n, 0);
    println!("Success!");
}

pub fn ch4_4_pra_11() {
    gen_title("ch4_4_pra_11", 18);

    #[derive(Debug, PartialEq)]
    struct EvenNum(i32);

    impl TryFrom<i32> for EvenNum {
        type Error = ();

        fn try_from(value: i32) -> Result<Self, Self::Error> {
            if value % 2 == 0 {
                Ok(EvenNum(value))
            } else {
                Err(())
            }
        }
    }

    assert_eq!(EvenNum::try_from(8), Ok(EvenNum(8)));
    assert_eq!(EvenNum::try_from(5), Err(()));

    let result: Result<EvenNum, ()> = 8i32.try_into();
    assert_eq!(result, Ok(EvenNum(8)));
    let result: Result<EvenNum, ()> = 5i32.try_into();
    assert_eq!(result, Err(()));

    println!("Success!");
}

pub fn ch4_4_pra_12() {
    gen_title("ch4_4_pra_12", 18);

    struct Point {
        x: i32,
        y: i32,
    }

    impl fmt::Display for Point {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "The point is ({}, {})", self.x, self.y)
        }
    }

    let origin = Point { x: 0, y: 0 };
    assert_eq!(origin.to_string(), "The point is (0, 0)");
    assert_eq!(format!("{}", origin), "The point is (0, 0)");

    println!("{}", origin);
}

pub fn ch4_4_pra_13() {
    gen_title("ch4_4_pra_13", 18);

    let parsed: i32 = "5".parse().unwrap();
    let turbo_parsed = "10".parse::<i32>().unwrap();
    let from_str = i32::from_str("20").unwrap();

    let sum = parsed + turbo_parsed + from_str;
    assert_eq!(sum, 35);

    println!("Success!");
}

pub fn ch4_4_pra_14() {
    gen_title("ch4_4_pra_14", 18);

    #[derive(Debug, PartialEq)]
    struct Point {
        x: i32,
        y: i32,
    }

    impl FromStr for Point {
        type Err = ParseIntError;

        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let coords: Vec<&str> = s
                .trim_matches(|p| p == '(' || p == ')')
                .split(",")
                .map(|x| x.trim())
                .collect();

            let x_from_str = coords[0].parse::<i32>()?;
            let y_from_str = coords[1].parse::<i32>()?;

            Ok(Point {
                x: x_from_str,
                y: y_from_str,
            })
        }
    }

    let p: Point = "(3, 4)".parse().unwrap();
    assert_eq!(p, Point { x: 3, y: 4 });

    println!("{:?}", p);

    println!("Success!");
}

pub fn ch4_4_pra_15() {
    gen_title("ch4_4_pra_15", 18);

    let raw_bytes = [0x78, 0x56, 0x32, 0x12];
    let num = unsafe { std::mem::transmute::<[u8; 4], u32>(raw_bytes) };
    println!("{}", num);

    let num = u32::from_ne_bytes(raw_bytes);
    println!("{}", num);

    let num = u32::from_le_bytes(raw_bytes);
    println!("{}", num);

    let num = u32::from_be_bytes(raw_bytes);
    println!("{}", num);

    let ptr = &0;
    let ptr_num_transmute = unsafe { std::mem::transmute::<&i32, usize>(ptr) };
    println!("{}", ptr_num_transmute);

    let ptr_num_cast = ptr as *const i32 as usize;
    println!("{}", ptr_num_cast);

    let ptr = &mut 0;
    let val_transmute = unsafe { std::mem::transmute::<&mut i32, &mut u32>(ptr) };
    println!("{}", val_transmute);

    let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) };
    println!("{}", val_casts);

    let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") };
    println!("{:?}", slice);

    let slice = "Rust".as_bytes();
    println!("{:?}", slice);

    println!("{:?}", b"Rust");
}
